home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-07-21 | 56.1 KB | 1,329 lines |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- GCOOPE Version 1.0
-
- Generic C-language Object Oriented Programming Environment Version 1.0
-
- by Brian L. Price
-
- Released as Public Domain July, 1994.
-
-
-
- Table of Contents
-
-
- I. Introduction to Objects....................................1
- A. Object-ively Defined....................................1
- B. Genericity isn't just for canned goods..................2
- C. C. Inheritance without genetics.........................3
- D. Introducing GCOOPE......................................3
-
- II. The GCOOPE Environment.....................................5
- A. Object handles..........................................5
- B. Class variables.........................................6
- C. Instance Variables......................................7
- D. Methods.................................................7
- E. Function Dispatching....................................9
- 1. 1. g is the Name.....................................9
- 2. The Smalltalk Connection............................11
- 3. Local method caching................................11
- 4. Steering the instance...............................13
- F. Classes and Pseudo Classes.............................14
- G. Flag Classes...........................................15
-
- III. Creating a class definition..............................16
- A. Layout of a class definition module...................16
- B. Method definition section.............................16
- C. Installation routine..................................17
-
- IV. Expansion and Growth......................................18
-
-
- Appendices
-
- A. Appendix A. The GCOOPE USER'S GROUP.......................19
- B. Appendix B. About the Author in case you're really bored..20
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- i
-
-
-
- GCOOPE Version 1.0 User's Guide
-
- By Brian L. Price July, 1994
-
- I. Introduction to Objects
-
- A. Object-ively Defined
-
- Before diving into GCOOPE, let us take a few
- moments to examine the concept object. My pocket
- dictionary provides a starting point with two
- interesting definitions:
-
- 1. Object - Something serving as a focus of
- attention or ACTION.
-
- 2. Object - (Grammer) A noun that receives or is
- affected by the action of a verb....
-
- An object is first of all a thing, something that
- exists in a perceptible form, in other words data.
- That data is the focus of actions, it is changed,
- translated, or simply accessed by a verb (method).
-
- If we consider the verb to be a method for
- performing an action, and that method is described as a
- computer algorithm, we have the 'active' portion of the
- definition.
-
- Another way of saying object is active data. Now
- how do we apply this concept to computer programming?
- We must first lay out some useful principles. Lets
- borrow some tried and true programming principles as a
- start:
-
- 1. Modularity - modular code is self contained
- (at least as much as possible), and it has a
- well defined interface to the outside world.
- Since our object concept is already a
- seperate entity from its surroundings,
- enforcing the principle of modularity helps
- to keep it that way.
-
- 2. Orthagonality - The set of methods that we
- define to act upon our object's data should
- be orthagonal. In other words if you define
- an add operation, you must define a subtract
- operation. This goes hand in hand with our
- first principle. If our set of methods is
- complete and orthagonal, then there is no
- need for outside intervention.
-
- So our concept of object now consists of a piece
- of data that can be acted upon by an orthagonal set of
- methods with a well defined interface, and all this is
- contained as a seperate entity from its surroundings.
- Lets call this encapsulation.
-
- 1
-
-
-
- Now, by itself, our encapsulated object concept
- isn't more powerful than procedurally written code.
- (Although it would be easier to debug.) We need a few
- more concepts to build upon what we already have.
-
-
- B. Genericity isn't just for canned goods.
-
- If you have ever been short on cash, or frugal,
- you have probably purchased a generic product.
- Something that is generic is the same as any other
- thing of the same type or class, at least in all the
- functional ways. A generic item can be substituted for
- any other item of the same type.
-
- What if we develop a set of encapsulated objects,
- a subset of whose methods are remarkably similar in
- function, lets say that those methods are math
- functions. Now if one of those objects has integer
- data and another has floating point data, an add
- operation performs the same type of action on both
- objects. Thus we could say that in this case add is a
- generic action.
-
- If we provide a suitable method for detecting
- which object should be called depending upon the data
- type, we can develop a generic function add. It won't
- matter if its operand is of type float or integer
- because the correct object method will perform the
- actual operation. Thus we have the concept of a
- generic function label.
-
- This concept makes our object concept a bit more
- powerful. Now, wherever we have similar operations
- performed on different types of data, we can define one
- label which we can then use for that operation no
- matter what the actual data type is. We have
- simplified our interface, since there are fewer
- function labels required.
-
- More importantly, we no longer have to know the
- exact type or structure of the piece of data we are
- manipulating, all we have to know is that the operation
- we want to perform is a valid one for that object. To
- simplify if the desired action is filling a basket with
- fruit, do we really care if it gets filled with peaches
- in place of tangerines? Genericity gives us a degree
- of data independence.
-
-
-
-
-
-
-
-
-
-
- 2
-
-
- C. C. Inheritance without genetics
-
- We now have encapsulated objects with generic
- methods, what could make this concept more powerful ?
- In traditional programming we push complexity down the
- procedure chain. The real work gets done in seperate
- functions that we define to do a job. This allows us
- to concentrate on the big picture without being
- overwhelmed by details. The layout of a program looks
- like an upside down tree structurally.
-
- What if we have written an object to do a simple
- task and now we want to do a more difficult task that
- has the simple task as a necessary sub-task.
- Traditionally, we would call a subroutine. We could do
- that with our objects, but is there a better way ?
-
- Consider the upside down structure tree of the
- traditional program to be a family tree and the answer
- is obvious. What if we could define a new object that
- would automatically gain all the capabilities and data
- structures of the old object ? This is the concept
- called inheritance. If we define a child object with
- the old object as its parent, we can gain all its
- abilities (methods) through inheritance.
-
- Can we do better ? Sure, we can allow multiple
- ancestory ie. more than one parent, we can allow
- partial ancestory ie. gaining only a subset of the
- parent's capabilities, and we can redefine the parent
- capabilities adding our own structure and actions on
- top of what we inherit.
-
- Inheritance lets us both change and build upon the
- characteristics of the parent. This concept is made
- even more powerful by our earlier insistance on
- encapsulation. The parent can be changed to adapt it
- to new requirements and as long as the original
- interface and capabilities are not changed or removed,
- it makes no difference to the child object.
-
-
- D. Introducing GCOOPE
-
- We have reached the point where we have developed
- a quite powerful and useful concept. Now how do we
- apply it ?
-
- Brute force is always a good first shot, so we
- could write a program module that would define a data
- type or structure and methods (ie functions) to perform
- actions upon it. Well, we'll probably need more than
- one so we'll have to create and track each....
- INSTANCE! Hmm, we have a set of these data regions or
- instances, and we need only one set of methods to act
- upon them since they are all members of the same,...
- CLASS!
-
-
- 3
-
-
- Okay so we have this set of methods and data
- structure definitions for a class of object, lets call
- this the class definition. We need some sort of
- instance tracking database, lets use a variable to
- represent each instance. Call it type object, so I
- guess the variables would be OBJECT HANDLES.
-
- There's the first step, now lets incorporate the
- concept of genericity. We need some way of tracking
- all these methods for each of the .... GENERIC (shape
- changing) functions. Heck, we need some way of
- tracking all these generic function labels. Routing
- all these generic calls is going to be as bad as
- running a taxi service in Manhattan, we need a ....
- DISPATCHER to tell them where to go.
-
- Now for inheritance, we'll just add our ancestor's
- methods and instance memory to our own, of course we
- need a way to add our own methods that will overwrite
- any inherited methods for the same generic, and we have
- to keep track of which instance of the parent class
- belongs to our own instance,... you know we need a
- couple of object classes just to do all these things.
-
- At this point GCOOPE politely knocks at your door
- offering its services. GCOOPE has lists to track
- object classes and instances, it has a powerful
- function dispatcher and instance tracking mechanism, in
- addition it addresses problems we haven't even
- considered yet in this discussion. Topics like default
- destructors, temporary object deletion, error handling,
- class definition objects, and more. Best of all GCOOPE
- is written in and for the C programming language, bare
- metal power cloaked in an object friendly environment.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 4
-
-
- II. The GCOOPE Environment
-
- In this section, we will explore the strengths and
- weaknesses of the GCOOPE system and its implementation.
- GCOOPE is a powerful system but there are pitfalls and costs
- in using it. GCOOPE, like most other real world systems, is
- a product of choices between often conflicting goals and the
- resulting system is defined by those design choices.
-
-
- A. Object handles
-
- The data type object, defined in both pcstruct.h
- and GCOOPE31.h, is primarily used as a 'handle' for an
- object class or instance. The type object is defined
- in such a way that it is always at least 32 bits in
- size. It is normally defined as a long integer.
-
- For practical purposes, you can consider the
- object handle to be the object although in actuality it
- serves as a special type of index/pointer with internal
- structure members. For the actual details of the
- object handle structure, consult the T.R.M. (Technical
- Reference Manual).
-
- A secondary use of the data type object is to
- return values from a method function. When used in
- this manner, it should be cast as the appropriate data
- type if it is being used to return something other than
- an object handle. See the basic class libraries and
- the gcoope10.h file for assistance macros.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 5
-
-
- B. Class variables
-
- Class variables are variables or data structures
- that are accessible to all instances of that class.
- They are static variables that are the same for all
- instances of the class.
-
- The structure for a class variable area is defined
- in the class definition, each class can have at most
- one class variable structure/area. Another way of
- stating this is to say that the class variable
- structure area is a shared memory area private to class
- members but shared among those same members. All class
- variables must be accessed as members of the class
- variable structure.
-
- WARNING: In GCOOPE it is possible to access the class
- variable area of another class. DON'T. This type
- of practice defeats the purpose of encapsulation.
- If a change occurs to the structure in the owning
- class, you are in the same situation that you
- would be in with C++ friends, or normal C code,
- namely code re-write and re-compile time!
-
- In order to access the class variable area use the
- public kernel function, getCVptr. Full details of this
- function is given in the T.R.M. The class variable
- area is automatically created when the class definition
- is installed.
-
- When a class definition is installing itself as an
- instance of class 'Class', the size of the class
- variable structure must be passed as the cvSize
- parameter.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 6
-
-
- C. Instance Variables
-
- Instance variables are variables or data
- structures that belong to an instance of a class. This
- is a private static memory area for the instance. Each
- instance of a class will have a separate instance
- variable memory area.
-
- The structure for an instance variable area is
- defined in the class definition. Each class may have
- at most one instance variable structure. All instance
- variables must be referenced as members of that
- structure.
-
- WARNING: In GCOOPE, it is possible to access the
- instance memory for another class, or ancestor
- instance. DON'T. This practice makes your code
- dependant on the internal structure of those other
- modules, it defeats the entire purpose of
- encapsulation. Using this type of practice will
- result in code that is full of side effects and
- cross dependancies.
-
- To create the instance variable memory area, you
- must use the public kernel function makeInst. Full
- details of this function is given in the T.R.M. This
- function should only be called within the constructor
- (New) method of a class. It must be called prior to
- any ancestor constructor calls.
-
- To access the instance variable memory area, you
- use the public kernel function getIVptr. Full details
- on the use of this function is given in the T.R.M.
-
- When a class definition is installing itself as an
- instance of the class 'Class', the size of the instance
- variable structure must be passed as the parameter
- ivSize.
-
-
- D. Methods
-
- The generic GCOOPE method prototype is defined as:
-
- typedef object (*method)(object,...);
-
- A function of type method takes at least one
- parameter of type object and returns a type object.
- The first passed parameter must always be an object
- handle of type object. Additional parameters may be
- passed.
-
-
-
-
-
-
-
-
- 7
-
-
- In our method type definition, you may observe the
- use of the variable argument parameter ... This is
- handy because we can use that one type method no matter
- how many parameters are actually required by an actual
- method. This does present some dangers.
-
- First, passing a pointer as a variable argument
- parameter is like running barefoot through a minefield.
- Second, passing different data types in a variable
- argument list is like adding machine gun and mortar
- fire to that minefield. Unless your name is Superman,
- you will take serious hits.
-
- At first glance, it seems we've put ourselves in a
- dilemma, we have a powerful abstraction that is too
- dangerous to use, right? Wrong. Why are you passing
- pointers to a method in the first place ??? You should
- be passing object handles! Object handles are much
- safer because they undergo some error checking and
- their internal structural integrity is verifiable. In
- fact, you can add even more error-checking on top of
- the built-in checks in your class definitions.
-
- As for multiple data types, we already have a type
- object which can be used to pass almost any other data
- type. Why not use it? If you only pass one parameter
- in the variable argument field and if you are careful
- in your design of object class definitions, it is
- convient and fairly safe to pass a pointer or other
- data type. However, with multiple parameters, take
- heed.
-
- 1. RULE #1
- When writing a method for use by an
- applications program, if more than one parameter
- is to be passed in the variable argument portion,
- always use type object for all variable argument
- list parameters, and always use an object handle
- to an object instance rather than any pointers to
- memory areas.
- Another solution is to use the experimental
- strong typing option. See typing.h. The best
- approach is probably to use a combination of the
- above advice, judicious use of strong typing and
- when in doubt be sure and use the return value
- typedefs.
-
-
-
-
-
-
-
-
-
-
-
-
-
- 8
-
-
- E. Function Dispatching
-
- The function dispatching and instance tracking
- system in GCOOPE version 1.0 is far more sophisticated
- than in the earlier. Used correctly, they can make
- your programming chores easier, used incorrectly you
- will need a good debugger.
-
- 1. 1. g is the Name
-
- The function g is GCOOPE's function
- dispatcher, its usage is deceptively simply. Even
- though complete details are given in the Technical
- Reference Manual for the GCOOPE kernel, I'll
- repeat the usage info here.
-
- returnObjectValue = g(generic)(objectInstance,
- [methodParms,...]);
-
- Where: returnObjectValue is a return value of
- type object that is returned from the dispatched
- method; generic is the generic function value of
- type generic; objectInstance is the object type
- object handle of the instance or class being acted
- upon; and the optional methodParms,.... are the
- parameters passed to the method.
-
- If you want the details of its operation, see
- the Technical Reference Manual, here, just take
- for granted that it works as advertised.
-
- WARNING: SEE RULE #1
-
- 1. Incorrect casting of the return value
- either in the calling routine or in the
- method executed. 32 bit values are
- always passed, however depending on the
- method, all 32 bits may not be valid.
- Be sure to clearly specify in the class
- definitions what values are being
- returned by their methods. Also,
- whenever possible all methods with the
- same generic name should return the same
- data type. Otherwise you will be using
- the alternate definition of generic.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 9
-
-
- 2. Passing the wrong type in the method
- parameter list. GCOOPE is a weakly
- typed system, method parameters are NOT
- type checked, so stay alert. Wherever
- possible in your method definitions be
- sure and validate the recieved
- parameters.
- If possible, use the experimental
- strong typing option. It DOES provide
- type checking for method parameters,
- although it is a bit awkward to use.
-
- 3. Passing a char or int type as the
- objectInstance parameter instead of an
- object type. Can you say "abnormal
- program termination" ?
-
- It cannot be stressed enough, GCOOPE is
- weakly typed, this is both a blessing and a curse,
- a strength and a weakness. If you are the type of
- programmer that commonly expects the compiler to
- catch or correct your type casting, I strongly
- suggest that you use the strong typing option and
- use the return value typedefs.
-
- Another point to watch for: with variable
- argument prototyping such as that used by GCOOPE,
- it is tempting to define methods for the same
- generic function that take a different number of
- parameters or totally different data types as
- arguments. DON'T. That is asking for trouble.
-
- The only exceptions to this are the generic
- functions New and Err, the definition of these
- functions require that you use different numbers
- and types of parameters. Just be careful and
- don't carry the practice any further than
- absolutely necessary.
-
-
- TIP: While it is handy to use the same
- generic function for many similar methods,
- make sure that the methods truly are similar
- enough to justify it. Not only are you
- tempted to use different parameter types or
- numbers as noted above, but you will also be
- slowing down your program when you improperly
- apply methods to generics. generic functions
- with large numbers of methods are slower in
- dispatching.
-
-
-
-
-
-
-
-
-
- 10
-
-
- 2. The Smalltalk Connection
-
- If you have previous experience with
- Smalltalk, GCOOPE will smell like home. There are
- a few snakes in the garden however. Smalltalk
- makes regular use of trivial methods, methods such
- as +. While you may define the equivalent Plus
- and the like generics in GCOOPE, don't use them
- where execution speed is important.
-
- You will have noticed that GCOOPE methods
- execute an order of magnitude faster than
- Smalltalk methods. This is because GCOOPE methods
- are compiled C code while Smalltalk methods are
- interpreted code. What may not be so readily
- apparent is that GCOOPE's function dispatching is
- very similar to Smalltalk's and so it is not much
- faster. What happens with 'trivial' methods is
- that the execution time for function dispatching
- dwarfs the execution time for the method. In
- other words, GCOOPE will slow down to near
- Smalltalk speeds when executing these types of
- methods.
-
- When speed is critical, and you only need to
- call such a method once or twice, do these
- 'trivial' methods locally where possible. For
- another idea see the next section.
-
- All in all, the use of Smalltalk techniques
- is generally a very good idea, GCOOPE is very
- close in concept to the idea of compiled
- Smalltalk. They share many of the same strengths
- and mannerisms. One trap to avoid is forgetting
- that GCOOPE has more capabilities with regards to
- inheritance than Smalltalk does, so don't miss out
- on reaping those benefits.
-
-
- 3. Local method caching
-
- If you are going to call the same method more
- than once or twice in the same statement block or
- routine, you can drastically decrease the
- execution time of the dispatching process. Just
- use the following call:
-
- methodToCall=p(generic, instanceObject);
-
- Where: methodToCall is a method type variable used
- to hold the method address; generic is the
- generic function index; and instanceObject is
- the object type object handle for the
- instance.
-
-
-
-
-
- 11
-
-
- For this technique to apply, instanceObject
- must remain constant, or must be a non-inherited
- flag class instance of the same constant class.
- (flag classes will be explained in detail later,
- also see the T.R.M.)
-
- Also if instanceObject is not a non-inherited
- flag class, you will have to make the following
- call prior to the one above:
-
- instanceObject = steer(ClassOfMethod,
- instanceObject);
-
- This will set the instanceObject's instance
- tracking variable to correctly point to the
- desired instance data.
-
- With all the above limitations, this
- technique will not be used often, it can however
- be used in some cases to get around the 'trivial'
- method penalty described in the previous section.
-
- PROGRAMMER'S NOTE: The best solution to the
- need for speed in function dispatching is to
- rewrite the dispatcher so that it does not make
- any function calls. Then if writing a platform
- dependant version, you can drop to assembly and
- hand-optimize the result of the first step. This
- is the path I used in tests of PCOOPE version 2.1
- and while the dispatcher has changed quite a bit,
- the new dispatcher should be capable of reaching
- comparable speeds. (In 2.1 the speed increase was
- quite remarkable (try >10x) and well worth the
- effort.) If you have a copy of version 2.1
- examine the dispatcher routine for hints.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 12
-
-
- 4. Steering the instance
-
- In the section above you caught your first
- glimpse of the function steer. It is used to
- 'steer' the instance tracking mechanism so that
- makeInst and getIVptr will work correctly.
- Normally this is done automatically by the
- dispatcher. However there are certain instances
- where you must call steer from within your class
- definitions.
-
- a. RULE #2
- The rule for the need for a manual call
- to steer is: any time you are calling a
- generic function that will dispatch to a
- method that is defined in an ancestor of the
- current class, you must use manual steer
- -ing. Prime examples of this situation occur
- in methods for the generics New and Kill (and
- to a lesser extent in Err). The procedure is
- fairly simple:
-
- retVal=g(generic)(steer(ancestor,
- instance),[parms]);
-
- Where: ancestor is the class object handle
- for the ancestor class; and instance is
- the object handle for the current
- instance.
-
- This situation occurs because the current
- instance is used by the dispatcher to determine
- what the current class is. If the current class
- and an ancestor class have methods for the same
- generic, you could never reach the ancestor method
- because the dispatcher would call the current
- class method. The above call 'fools' the
- dispatcher into believing that the ancestor class
- is already the current class and so the call goes
- through. Also see the macro ST() in gcoope10.h.
-
- Some commercial products similar in concept
- to GCOOPE initialize the ancestor classes for you
- prior to calling the child class's method for New.
- The problem with this is, that either you end up
- with dozens of parameters in the call (to pass all
- the ancestor initialization parms and don't ask me
- how you track that with multiple ancestory) or you
- don't have any control over ancestor
- initialization. Frankly, either case is
- unacceptable.
-
-
-
-
-
-
-
-
- 13
-
-
- The above solution isn't what I sought, but
- it is usable and achieves the desired purpose.
- The only other solutions I could find added way
- too much complexity to the kernel code and still
- didn't solve the occasional problem of calling an
- ancestor method outside of New or Kill. You
- would have a bigger, slower function dispatcher,
- and still need the steer routine!
-
- You will also need to use the above technique
- in your Kill methods wherever they occur, for
- exactly the same reasons. Another place where you
- may find yourself in need of the above solution is
- when you redefine an ancestor method in a way that
- adds to the inherited method. In other words,
- where you still need to call the ancestor method.
-
- Another way to look at the above is, if you
- don't know the ancestor class you don't need to
- call steer. Applications programs should never
- need it.
-
- Performance wise, the extra call doesn't hurt
- you very much. First because the dispatcher won't
- have to go through a steer procedure, and second
- because it will only occur normally in the
- constructor, destructor, or error handler portion
- of the class definition. New and Kill methods are
- one time cost routines per object instance and if
- your code is calling Err very often something is
- wrong <GRIN>.
-
-
- F. Classes and Pseudo Classes
-
- We have not yet reached the point where we are
- ready to begin writing class definitions, but in order
- to understand some of the next section, you need to
- introduce yourself to some of the concepts.
-
- Classes are comprised of an optional class
- variable structure definition, an optional instance
- variable structure definition, method definitions, and
- an installation function.
-
- Pseudo classes are classes that cannot be properly
- inherited, they have no class or instance variable
- structure definitions, although they may make use of
- structure definitions defined internally or externally.
- Pseudo classes may define methods, although they don't
- have to. They may also define non-generic functions.
- They must include an installation procedure.
-
-
-
-
-
-
-
- 14
-
-
- An installation procedure installs the class or
- pseudo class definition into the GCOOPE system. It is
- responsible for inheritance and genericity. For a
- class definition, it is also the place where class
- variables may be initialized.
-
- Non-generic functions are simply standard C
- library type functions instead of generic function
- methods.
-
- Class definitions are where objects are defined,
- pseudo class definitions interface to the platform
- and/or hardware. Pseudo class definitions are also
- used to expand GCOOPE's kernel adding necessary or
- optional functionality. The pseudo class concept was
- developed because of a desire to treat kernel expansion
- in a modular way that could make use of kernel
- resources used by normal class definition modules.
-
-
- G. Flag Classes
-
- The last topic to cover in the GCOOPE environment
- is the flag class. A flag class uses a portion of the
- object handle as an index to its class object. This
- means that the lower 16 bits of the object handle are
- no longer needed by the GCOOPE system.
-
- A flag class uses those 16 bits as its instance
- variable storage area. Thus, for the overhead of a
- simple flag check, flag classes can implement classes
- such as Boolean, Char, Int, etc. with no instance
- memory being dynamically allocated! For full details
- of the object handle structure see the T.R.M.
-
- A flag class is subject to certain limitations.
- First, it cannot inherit any class which has instance
- variables. Second, it must check to see if it is the
- owner of the instance object handle in each method
- prior to accessing the instance variable. Third the
- New method for such a class must be dual purpose. If
- it is being inherited, it must behave exactly as a
- normal class.
-
- Basically, the flag class must be careful to check
- whether or not it has been inherited with respect to
- the current instance. If it has been, it must behave
- exactly like a normal class. (Note: a flag class's
- ivSize must be given as sufficient to store its
- variable type.) Before attempting to create a flag
- class definition, it is strongly suggested that you
- study the relevant portions of the T.R.M. closely and
- also be sure to check the example code provided.
-
-
-
-
-
-
- 15
-
-
- III. Creating a class definition
-
- A. Layout of a class definition module
-
- The first statement in a class definition is
- #define CLASS <className>. This names the class and
- becomes the symbol string name for it. The second
- statement is #include "GCOOPE31.h" and the third
- statement is object CLASS;.
-
- Following those statements should be your
- structure definitions for the class variable and
- instance variable structures. These structures are
- optional. Hint: instead of creating them as a named
- structure, typedef them as a structure.
-
- Next should be the class constructor method
- definition, followed by any user defined method
- definitions and by a destructor and error handling
- method if desired.
-
- The final portion of the class definition is the
- class installation function definition.
-
-
- B. Method definition section
-
- The only method you must define is a constructor.
- It should call makeInst and then call the constructors
- of each superClass by:
- p(New)(steer(superClass,instance),[initParms]);
-
- Other than that, you're on your own as far as
- methods go. Just make sure they all fit the following
- prototype: retValType methodName(object,...);.
-
- A few points to remember however, if you
- dynamically allocate memory within your object:
-
- 1. use the kernel memory management shells
- s_calloc, s_free, s_malloc, and s_realloc.
-
- 2. write a method for Kill that frees the memory
- and calls p(Kill)(steer(superClass,
- instance)); for each superClass. (immeadiate
- parent) and ending with p(Kill)(Object,
- instance);.
-
-
-
-
-
-
-
-
-
-
-
-
- 16
-
-
- C. Installation routine
-
- The name of the class installation routine MUST be
- given as the macro CLASS_INSTALL. This insures
- compatibility with the class installation macros. The
- first statement after any local variable and pointer
- declarations is:
-
- CLASS =
- p(New)(Class, sizeof(classVarStruct),
- sizeof(instanceVarStruct), [SuperClass object
- handle list], END);
-
- This creates the class definition, you may now
- optionally get a pointer to the class variables area by
- getCVptr and initialize the class variables.
-
- The next step is to add each method, this is done
- by:
- addPMthd(CLASS, genericName, methodAdr);
-
- You can also block ancestor methods for a generic
- via rmvPMthd (see T.R.M.). This is useful for ancestor
- methods which should not be directly called except from
- a method defined by this class definition.
-
- A note here about inheritance, the call to
- p(New)(Class,...) will setup a description of an
- instance memory block for instances of this class.
- That description includes the instance memory blocks
- for all ancestors. After performing that setup, the
- class creation method will add ALL the ancestor methods
- to the current class automatically. The order that you
- specify superClasses (immediate ancestors) is
- important. Those given first in the list will take
- precedence over later entries. Their methods will
- overwrite any conflicting or overlapping methods for a
- generic. When you use addPM or rmvPM you will
- overwrite or remove any listed ancestor method for the
- generic in question.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 17
-
-
- IV. Expansion and Growth
-
- In the short documentation with the PCOOPE version 2.1
- release, I foolishly stated that the interface was written
- in stone and that all expansion and growth would occur
- through the class definitions. Alas, as so aptly put by the
- first user's group member, G/PCOOPE isn't ready for that.
- He was 100% correct.
-
- In version 1.0 I have attempted to write the kernel in
- an expandable manner. That is one reason why the provided
- code is optimized for little else than debugging. For each
- target platform, an optimized version of the appropriate
- kernel module(s) should be created. Low level functions
- that prove necessary can be added via the pseudo class
- expansion module route. In the design of this system, I
- have attempted to provide for the possiblity of future
- expansion at each level of the system.
-
- GCOOPE has potential as an application framework. For
- that potential to be realized standard, generic, well
- defined, and expandable interface specifications need to be
- developed. Available public domain libraries that help to
- meet these needs should be incorporated as expansion
- modules. No doubt, some custom code will have to be
- written. The GUI portion alone will prove quite an
- undertaking, if GCOOPE is to realize its potential a GUI
- specification must provide a path to compatibility with
- Windows, X-windows, and other popular GUI environments.
-
- GCOOPE also has potential as an object oriented
- operating system extension. In this concept, the GCOOPE
- kernel would be a system resource with instantiated memory.
- Such an extension would have to include the ability to share
- dynamically loaded modules. This type of extension to the
- GCOOPE framework is not as difficult as it might sound at
- first, GCOOPE could be made available as a process on a Mach
- 3.0 or QNX microkernel. There would, no doubt, be many
- additional demands placed upon the GCOOPE system however.
-
- As of this writing, GCOOPE is in its infancy, at the
- very least it serves as an exploratory framework into the
- next generation of object oriented programming languages,
- application frameworks, and operating systems, at the most
- .... you be the judge. Or better yet, join the GCOOPE
- user's group and join in the expansion and implementation of
- the GCOOPE system.
-
-
-
-
-
-
-
-
-
-
-
-
- 18
-
-
- Appendix A. Appendix A. The GCOOPE USER'S GROUP
-
-
- JOIN THE GCOOPE USER'S GROUP!
-
-
- For a one year membership send check/money order in the
- amount of $20.00, (made payable to Brian Lee Price) to the
- address below:
-
- Brian Lee Price
-
- GCOOPE USERS GROUP
-
- RD2 BOX239AA
-
- CLEARVILLE, PA. 15535
-
- Please include my middle name to avoid local post office
- difficulties :).
-
-
- User's group members receive the latest updates to the
- GCOOPE system, new class libraries, expansion modules, etc.
- Limited free technical support over the phone is available,
- and access is granted to a User's group only private limited
- access bbs, you will be added to the quarterly newsletter
- mailing list, and other services are available.
-
- It is my hope that the user's group members will
- participate in the growth of the GCOOPE system, expanding
- its libraries and its capabilities. This way, all user's of
- the framework will benefit from a degree of co-operation
- that is often impossible to achieve with a commercial
- product.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 19
-
-
- Appendix B. Appendix B. About the Author (in case you're really
- bored)
-
- The author is a starving artist type, currently
- unemployed and living in the mountains of south central
- Pennsylvania (Hi-technology's equivalent of Bumf---, Egypt).
- First introduced to computers after a tour in the USAF as a
- television studio technician in 1982. First programming
- experience in assembly language on Intertec (who?)
- SuperBrain II CP/M and Atari 800XL machines.
-
- Catching the PC wave, the author worked throughout most
- of the 80s as a computer technician/consultant ending up
- working in the computer evaluation laboratory of Entre'
- computer corporate where he was allowed to play with early
- networks, CAD/CAM, and the first 386 machines. For the late
- 80's and early 90's the author was a self employed
- electronic systems and circuit designer/consultant having
- some success with early video frame digitizer designs for
- the Apple Macintosh II before they butchered its expansion
- slot capacity.
-
- The last few years spent working with embedded systems
- such as traffic control computers and monitors and playing
- around with computer languages, the author began his
- programming career in C in 1993. GCOOPE is his first
- publicly released software package. When not working on the
- GCOOPE project or his (t)rusty '70 Ford F-150, the author is
- working with local business and political interests to
- establish a free public access bbs and Internet link in his
- home county.
-
- Anyone need the above talents for a paid job???
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 20
-